/*
 * $Id$
 * Sleeper
 *
 * Created by Jon Gordon on 10/28/08
 * Copyright Jon Gordon.  All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to 
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#import "QELogWindowController.h"

#import "QELogDocument.h"
#import "QELogModel.h"
#import "QEOperator.h"


@interface QELogWindowController (private)
#pragma mark PRIVATE FIELDS
- (QELogWindowFields *)fields;
- (void)setFields:(QELogWindowFields *)newValue;

#pragma mark OPERATIONS
/*
 * Callback method for when display clock's timer fires.
 */
- (void)clockUpdate:(NSTimer *)theTimer;

- (void)updateDupeCallWarning;
@end


@implementation QELogWindowController (private)
#pragma mark PRIVATE FIELDS
- (QELogWindowFields *)fields
{
    //    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[fields retain] autorelease];
} // fields

- (void)setFields:(QELogWindowFields *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (newValue != fields) {
        id temp = fields;
        fields = [newValue retain];
        if (temp) {
            [temp removeObserver:self
                      forKeyPath:@"entrySrc"];
            [temp release];
        } // if
        
        if (newValue) {
            [fields addObserver:self
                     forKeyPath:@"entrySrc"
                        options:NSKeyValueObservingOptionNew
                        context:NULL];
        } // if
    } // if
} // setFields:


#pragma mark KEY-VALUE CODING & OBSERVING
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if ([self fields] == object) {
        if ([keyPath isEqual:@"entrySrc"]) {
            id newValue = [change objectForKey:NSKeyValueChangeNewKey];
            if ([[NSNull null] isEqual:newValue]) {
                newValue = nil;
            } // if
            
            QELogModel *model = [[self doc] model];
            [model setExchangeRcvd:newValue];
            [[self fields] setValuesForKeysWithDictionary:[model allElements]];
            [self updateDupeCallWarning];
        } // if
    } else if (operatorsController == object) {
        if ([keyPath isEqual:@"selectedObjects"]) {
            [self setCanDeleteOperator:([[operatorsController selectedObjects] count] > 0)];
        } // if
    } // else if
} // observeValueForKeyPath:ofObject:change:context:


#pragma mark OPERATIONS
- (void)updateDupeCallWarning
{
    if ([[[self doc] model] isCallInLog:[[self fields] call]]) {
        [callField setBackgroundColor:[NSColor yellowColor]]; 
    } else {
        [callField setBackgroundColor:[NSColor textBackgroundColor]];
    } // else
} // updateDupeCallWarning


- (void)windowDidLoad
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [self setFields:[[[QELogWindowFields alloc] init] autorelease]];

    [fieldController setContent:[self fields]];
    [modelController setContent:[[self doc] model]];
    [[self window] setDelegate:self];
    
    // the log window has a UTC clock that updates in real time
    NSDateFormatter *timeFieldFormatter = [[[NSDateFormatter alloc] init] autorelease];
    [timeFieldFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [timeFieldFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    [timeFieldFormatter setDateFormat:@"dd-MMM-yyyy HH:mm:ss 'UTC'"];
    [[timeField cell] setFormatter:timeFieldFormatter];
    [[self fields] setCurrentTime:[NSDate date]];
    
    // make sure that the contacts table also shows the time in UTC, too
    NSDateFormatter *timeColumnFormatter = [[[NSDateFormatter alloc] init] autorelease];
    [timeColumnFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [timeColumnFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    [timeColumnFormatter setDateFormat:@"dd-MMM HH:mm:ss"];
    [[[contactsTable tableColumnWithIdentifier:@"time"] dataCell] setFormatter:timeColumnFormatter];    
    
    clockTimer = [NSTimer scheduledTimerWithTimeInterval:0.29
                                                  target:self
                                                selector:@selector(clockUpdate:)
                                                userInfo:nil
                                                 repeats:YES];
    
    // need to keep track of the operators controller's selection so we can tell
    // whether the delete operator button is enabled in the entry window
    [operatorsController addObserver:self 
                          forKeyPath:@"selectedObjects" 
                             options:NSKeyValueObservingOptionNew 
                             context:NULL];
    
    [[self doc] updateSentExchange];
} // windowDidLoad


- (void)clockUpdate:(NSTimer *)theTimer
{
    //    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self fields] setCurrentTime:[NSDate date]];
} // clockUpdate:


- (void)windowWillClose:(NSNotification *)notification
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [clockTimer invalidate];
    
    NSLog(@"  clearing contents of controllers");
    [modelController setContent:nil];

    NSLog(@"  removing log window controller from list of observers");
    [self setFields:nil];
} // windowWillClose:
@end


@implementation QELogWindowController
#pragma mark LIFECYCLE METHODS
- (void)dealloc
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [self setFields:nil];
    
    [super dealloc];
} // dealloc


#pragma mark ACTIONS
- (IBAction)clearAction:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self doc] clearExchange];
} // clearAction:


- (IBAction)enterAction:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self doc] createQsoWithNewExchange:@""];
} // enterAction:


- (IBAction)exportCabrilloAction:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self doc] exportCabrillo];
} // exportCabrilloAction:


- (IBAction)showSectionsAction:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self doc] showSections];
} // showSectionsAction:


- (IBAction)editEntryInfo:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    tmpEntryData = [[[[self doc] model] entryData] copy];
    [entryDataController setContent:tmpEntryData];
    [NSApp beginSheet:entryDataSheet
       modalForWindow:[self window]
        modalDelegate:nil
       didEndSelector:NULL
          contextInfo:NULL];
} // editEntryInfo


- (IBAction)addOperatorAction:(id)sender
{
    /*
     * This method is adapted from chapter 9 of Hillegass, Cocoa 
     * Programming (3rd ed.).
     */
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSWindow *w = [operatorsTable window];
    
    // Try to end any editing that is taking place
    BOOL editingEnded = [w makeFirstResponder:w];
    if (!editingEnded) {
        NSLog(@"  WARNING: unable to end editing");
        return;
    } // if
    NSUndoManager *undo = [self undoManager];
    
    // Has an edit occurred already in this event?
    if ([undo groupingLevel]) {
        // Close the last group
        [undo endUndoGrouping];
        // Open a new group
        [undo beginUndoGrouping];
    } // if
    // Create the record for the new operator
    QEOperator *op = [operatorsController newObject];
    
    // Add it to the content array of 'operatorController'
    [operatorsController addObject:op];
    [op release];
    
    // Re-sort (in case the user has sorted a column)
    [operatorsController rearrangeObjects];
    
    // get the sorted array
    NSArray *a = [operatorsController arrangedObjects];
    
    // Find the object just added
    int row = [a indexOfObjectIdenticalTo:op];
    NSLog(@"  starting edit of %@ in row %d", op, row);
    
    // Begin the edit in the first (and only) column
    [operatorsTable editColumn:0
                           row:row
                     withEvent:nil
                        select:YES];
    
} // addOperatorAction:


- (IBAction)deleteOperatorAction:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [operatorsController removeObjects:[operatorsController selectedObjects]];
} // deleteOperatorAction:


- (IBAction)closeEntryDataSheet:(id)sender
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [NSApp endSheet:entryDataSheet];
    [entryDataSheet orderOut:self];
    
    QELogModel *model = [[self doc] model];
    if ([[sender title] isEqual:@"OK"] && ![[model entryData] isEqual:tmpEntryData]) {
        
        NSLog(@"  overwriting entry data");
        [entryDataController commitEditing];
        [model setEntryData:tmpEntryData];
        [[self doc] updateChangeCount:NSChangeDone];
        [[self doc] updateSentExchange];
    } // if
    
    // clean up the entry data now, rather than wait until closing,
    // because I'm neurotic about memory leaks
    [entryDataController setContent:nil];
    [tmpEntryData release];
} // closeEntryDataSheet:


#pragma mark PROPERTIES
- (NSString *)outExchange
{
    return [[self fields] outExchange];
} // outExchange

- (void)setOutExchange:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self fields] setOutExchange:newValue];
} // setOutExchange:


- (BOOL)canDeleteOperator
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return canDeleteOperator;
} // canDeleteOperator


- (void)setCanDeleteOperator:(BOOL)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    canDeleteOperator = newValue;
} // setCanDeleteOperator:


- (NSString *)entrySrc
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[self fields] entrySrc];
} // entrySrc

- (void)setEntrySrc:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[self fields] setEntrySrc:newValue];
} // setEntrySrc:


- (QELogDocument *)doc
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[doc retain] autorelease];
} // log

- (void)setDoc:(QELogDocument *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    // not retained to avoid retain loops
    doc = newValue;
    
    if (nil == newValue) {
        NSLog(@"  setting document to nil");
    } else {
        NSLog(@"  setting document to not-nil");
    } // else
} // setDoc:
@end
